/*jslint */
/*global isNaN, setTimeout, Class */

var http = require('http'),
    util = require('util'),
    url = require('url'),
    querystring = require('querystring'),
    fs = require('fs');

var configCache = {},
    configLocks = {};

function loadConfig(configPath, ttl, callback) {
    'use strict';
    if (typeof callback !== 'function') {
        throw new TypeError('');
    }
    if (configCache[configPath]) {
        setTimeout(function () {
            callback(undefined, configCache[configPath]);
        }, 1);
    } else {

        fs.readFile(configPath, function (error1, content) {
            if (error1) {
                callback(new TypeError(error1));
            } else {
                try {
                    content = JSON.parse(content.toString('utf8'));
                    configCache[configPath] = content;
                } catch (error2) {
                    callback(new TypeError(error2.message));
                    return;
                }
                if (typeof ttl === 'number' && !isNaN(ttl) && ttl % 1 > 0) {
                    setTimeout(function () {
                        delete configCache[configPath];
                    }, ttl % 1);
                }
            }
        });
    }
}

http.createServer(function (request, response) {
    function errorBadRequest() {
        return JSON.stringify({
            'result' : null,
            'error' : {
                'code' : 0,
                'message' : 'Bad request'
            }
        });
    }
    function errorNotFound() {
        return JSON.stringify({
            'result' : null,
            'error' : {
                'code' : 1,
                'message' : 'Not found'
            }
        });
    }

    var hostname    = String(request['headers']['host']),
        urlObject   = url.parse(request['url']),
        pathname    = String(urlObject['pathname']),
        params      = querystring.parse(urlObject['query']),
        wrapper     = '#{json}',
        contentType = 'application/json; charset=utf-8';
    // Избавляемся от порта в названии хоста.
    if (hostname.indexOf(':') !== -1) {
        hostname = hostname.slice(0, hostname.indexOf(':'));
    }
    // Обработчик запросов JSONP.
    if (params['callback'] && typeof params['callback'] === 'string' && /^[a-z_][_0-9a-z]*(?:\.[a-z_][_0-9a-z]*)*(?:\(\d+\))?$/i.test(params['callback'])) {
        contentType = 'application/x-javascript; charset=utf-8';
        wrapper = params['callback'] + '(#{json});';
    }

    if (pathname.indexOf('/service/administrator/') === 0) {

        response.writeHead(200, {
            'Content-Type': contentType
        });
        response.end(wrapper.replace(/#\{json\}/i,
            JSON.stringify(params)));


//        if (/[a-z](-[a-z]|[0-9a-z])*/) {
//
//        }

//        (function (pathname) {
//            var service = [];
//            pathname.slice(23).split('/').forEach(function (element) {
//                element = element.slice(0, 1).toUpperCase() + element.slice(1);
//                element = element.replace(/-[a-z]/, function (match) {
//                    return match.slice(1).toUpperCase();
//                });
//                element = element.replace(/-/g, '_');
//                service.push(element);
//            });
//            response.end(service.join('.'));
//        }(pathname));
    } else if (pathname === '/service/administrator') {
        response.end('error');
    } else if (pathname.indexOf('/service/') === 0) {
        response.writeHead(200, {'Content-Type': 'text/json'});
        response.end(util.inspect(pathname));
        //response.end(util.inspect(request));
    } else if (pathname === '/service') {
        response.end('error');
    }

}).listen(1337, 'localhost');


/**
 * Класс веб-сервера.
 *
 * @class
 * @name Phantom
 * @extends Class
 */
var Phantom = Class.$extend({

    /**
     * Базовая директория проекта.
     *
     * @private
     * @field
     * @name Phantom#baseDirectory
     * @see Phantom#getBaseDirectory
     * @type {String|null}
     */
    baseDirectory : null,

    /**
     * Директория проекта смотрящая в веб.
     *
     * @private
     * @field
     * @name Phantom#publicDirectory
     * @see Phantom#getPublicDirectory
     * @type {String|null}
     */
    publicDirectory : null,

    /**
     * Директория конфигураций.
     *
     * @private
     * @field
     * @name Phantom#configDirectory
     * @see Phantom#getConfigDirectory
     * @type {String|null}
     */
    configDirectory : null,

    /**
     * Получить базовую директорию проекта.
     *
     * @public
     * @function
     * @name Phantom#getBaseDirectory
     * @see Phantom#baseDirectory
     * @return {String|null}
     */
    getBaseDirectory : function () {
        'use strict';
        return this.baseDirectory;
    },

    /**
     * Получить директорию проекта смотрящую в веб.
     *
     * @public
     * @function
     * @name Phantom#getPublicDirectory
     * @see Phantom#publicDirectory
     * @return {String|null}
     */
    getPublicDirectory : function () {
        'use strict';
        return this.publicDirectory;
    },

    /**
     * Получить директорию конфигураций.
     *
     * @public
     * @function
     * @name Phantom#getConfigDirectory
     * @see Phantom#configDirectory
     * @return {String|null}
     */
    getConfigDirectory : function () {
        'use strict';
        return this.configDirectory;
    },

    /**
     * Конструктор.
     *
     * @public
     * @function
     * @name Phantom#$init
     * @param {Object} options Объект конфигурирования сервера.
     * @param {Function} callback Обработчик окончания запуска.
     * @return {void}
     */
    $init : function (options, callback) {
        'use strict';
        var self = this,
            baseDirectory,          // Базовая директория проекта.
            publicDirectory,        // Директория смотрящая в веб.
            useStaticCache = false, // Признак использования кеширования для статики.
            useDebugging = false;   // Признак использования отладки.
        function difference(start, end) {
            var startTimestamp = Number(start),
                endTimestamp = Number(end),
                difference = ('  ' + String((endTimestamp - startTimestamp) / 1000 + 0.0001)).split('.'),
                major = difference[0].substring(-3),
                minor = difference[1].substring(0, 3);
            return major + '.' + minor + ' sec: ';
        }
        Deferred.$create([
            // -----------------------------------------------------------------
            // Параметр использования отладчика.
            function (success) {
                if (typeof options['useDebugging'] === 'string') {
                    // Параметр отладчика заданные строкой.
                    useDebugging = ['true', 'yes', 'on', '1'].indexOf(options['useDebugging'].
                        replace(/^\s+/g, '').replace(/\s+$/g, '').toLowerCase()) !== -1;
                } else if (typeof options['useDebugging'] === 'number') {
                    // Параметр отладчика заданный числом.
                    useDebugging = options['useDebugging'] > 0;
                } else if (typeof options['useDebugging'] === 'boolean') {
                    // Параметр отладчика заданный булевым значением.
                    useDebugging = options['useDebugging'];
                }
                success();
            },
            // -----------------------------------------------------------------
            // Проверяем, что задана директория baseDirectory.
            function (success, failure) {
                if (typeof options['baseDirectory'] !== 'string') {
                    // Путь к директории не является строкой.
                    failure('Not configured required option "baseDirectory"!');
                } else {
                    // Сохраняем путь в локальной переменной.
                    baseDirectory = options['baseDirectory'];
                    success();
                }
            },
            // Ищем абсолютный путь к директории.
            function (success, failure) {
                var time = new Date();
                fs.realpath(baseDirectory, function (error, resolved) {
                    if (DEBUGGER && useDebugging) {
                        // Выводим отладочную информацию в консоль.
                        cli.debug(difference(time, new Date()) + 'fs.realpath: ' + JSON.stringify(baseDirectory));
                    }
                    if (error) {
                        // Путь не найден или доступ запрещен.
                        failure('Path ' + JSON.stringify(baseDirectory) + ' not found or access denied!');
                    } else {
                        baseDirectory = resolved;
                        success();
                    }
                });
            },
            // Проверяем, что параметр указывает на директорию.
            function (success, failure) {
                var time = new Date();
                fs.stat(baseDirectory, function (error, stats) {
                    if (DEBUGGER && useDebugging) {
                        // Выводим отладочную информацию в консоль.
                        cli.debug(difference(time, new Date()) + 'fs.stat: ' + JSON.stringify(baseDirectory));
                    }
                    if (error) {
                        failure(error);
                    } else if (stats && stats.isSymbolicLink()) {
                        Deferred.$create([
                            // Определяем путь, на который
                            // указывает символьная ссылка.
                            function (success, failure) {
                                fs.readlink(baseDirectory, function(error, resolved) {
                                    if (DEBUGGER && useDebugging) {
                                        // Выводим отладочную информацию в консоль.
                                        cli.debug(difference(time, new Date()) + 'fs.readlink: ' + JSON.stringify(baseDirectory));
                                    }
                                    if (error) {
                                        failure(error);
                                    } else {
                                        baseDirectory = resolved;
                                        success();
                                    }
                                });
                            },
                            // Проверяем, что путь по символьной
                            // ссылке является директорией.
                            function (success, failure) {
                                fs.stat(baseDirectory, function (error, stats) {
                                    if (DEBUGGER && useDebugging) {
                                        // Выводим отладочную информацию в консоль.
                                        cli.debug(difference(time, new Date()) + 'fs.stat: ' + JSON.stringify(baseDirectory));
                                    }
                                    if (error) {
                                        failure(error);
                                    } else if (stats && !stats.isDirectory()) {
                                        // Путь не является директорией.
                                        failure('Path ' + JSON.stringify(baseDirectory) + ' is not a directory!');
                                    } else {
                                        success();
                                    }
                                });
                            }
                        ], function (error) {
                            if (error) {
                                failure(error['message']);
                            } else {
                                success();
                            }
                        }).run();
                    } else if (stats && stats.isDirectory()) {
                        success();
                    } else {
                        // Базовый путь проекта не является лиректорией.
                        failure('Path ' + JSON.stringify(baseDirectory) + ' is not a directory!');
                    }
                });
            },
            // Устанавливаем свойство объекта.
            function (success) {
                self.baseDirectory = baseDirectory;
                success();
            },
            // ---------------------------------------------------------------------------------------------------------
            // Проверяем, что задана директория publicDirectory.
            function (success, failure) {
                var optionType = typeof options['publicDirectory'];
                if (optionType !== 'undefined' && optionType !== 'string') {
                    // Путь к директории не является строкой.
                    failure('Option \'publicDirectory\' is not a string!');
                } else if (optionType === 'string') {
                    // Переопределяем значение по умолчанию.
                    publicDirectory = path.join(baseDirectory, options['publicDirectory']);
                    success();
                } else {
                    // Значение по умолчанию.
                    publicDirectory = path.join(baseDirectory, 'public');
                    success();
                }
            },
            // Ищем абсолютный путь к директории.
            function (success, failure) {
                var time = new Date();
                fs.realpath(publicDirectory, function (error, resolved) {
                    if (DEBUGGER && useDebugging) {
                        // Выводим отладочную информацию в консоль.
                        cli.debug(difference(time, new Date()) + 'fs.realpath: ' + JSON.stringify(publicDirectory));
                    }
                    if (error) {
                        // Путь не найден или доступ запрещен.
                        failure('Path ' + JSON.stringify(publicDirectory) + ' not found or access denied!');
                    } else {
                        publicDirectory = resolved;
                        success();
                    }
                });
            },
            // Проверяем, что параметр указывает на директорию.
            function (success, failure) {
                var time = new Date();
                fs.stat(publicDirectory, function (error, stats) {
                    if (DEBUGGER && useDebugging) {
                        // Выводим отладочную информацию в консоль.
                        cli.debug(difference(time, new Date()) + 'fs.stat: ' + JSON.stringify(publicDirectory));
                    }
                    if (error) {
                        failure(error);
                    } else if (stats && stats.isSymbolicLink()) {
                        Deferred.$create([
                            // Определяем путь, на который
                            // указывает символьная ссылка.
                            function (success, failure) {
                                fs.readlink(publicDirectory, function(error, resolved) {
                                    if (DEBUGGER && useDebugging) {
                                        // Выводим отладочную информацию в консоль.
                                        cli.debug(difference(time, new Date()) + 'fs.readlink: ' + JSON.stringify(publicDirectory));
                                    }
                                    if (error) {
                                        failure(error);
                                    } else {
                                        publicDirectory = resolved;
                                        success();
                                    }
                                });
                            },
                            // Проверяем, что путь по символьной
                            // ссылке является директорией.
                            function (success, failure) {
                                fs.stat(publicDirectory, function (error, stats) {
                                    if (DEBUGGER && useDebugging) {
                                        // Выводим отладочную информацию в консоль.
                                        cli.debug(difference(time, new Date()) + 'fs.stat: ' + JSON.stringify(publicDirectory));
                                    }
                                    if (error) {
                                        failure(error);
                                    } else if (stats && !stats.isDirectory()) {
                                        // Путь не является директорией.
                                        failure('Path ' + JSON.stringify(publicDirectory) + ' is not a directory!');
                                    } else {
                                        success();
                                    }
                                });
                            }
                        ], function (error) {
                            if (error) {
                                failure(error['message']);
                            } else {
                                success();
                            }
                        }).run();
                    } else if (stats && stats.isDirectory()) {
                        success();
                    } else {
                        // Базовый путь проекта не является лиректорией.
                        failure('Path ' + JSON.stringify(publicDirectory) + ' is not a directory!');
                    }
                });
            },
            // Устанавливаем свойство объекта.
            function (success) {
                self.publicDirectory = publicDirectory;
                success();
            }
        ], function (error) {
            // Если задан обработчик, то делегируем событие
            // окончания процесса запуска в обработчик.
            if (typeof callback === 'function') {
                if (error) {
                    // Необходим только текст ошибки.
                    error = error['message'];
                }
                callback.call(self, error);
            }
        }).run();
    },

    reload : function () {},

    stop : function () {}

});




/**
 * Класс списка панелей.
 *
 * @class
 * @name Jedi.ColumnsList
 * @extends List
 */
Jedi.ColumnsList = List.$extend({

    /**
     * Конструктор.
     *
     * @public
     * @function
     * @name Jedi.ColumnsList#$init
     * @param {Object} config
     * @return {void}
     */
    $init : function (config) {
        'use strict';
        var name, type,
            list = [];
        config = config || {};
        for (name in config) {
            if (config.hasOwnProperty(name)) {
                type = String(config[name] || '').toLowerCase() || 'text';
                type = type.slice(0, 1).toUpperCase() + type.slice(1);
                if (Jedi.Column[type] instanceof Jedi.Column) {
                    list.push(Jedi.Column[type].$create(name, config[name]));
                } else {
                    list.push(Jedi.Column.Text.$create(name, config[name]));
                }
            }
        }
        this.$super(list);
    }

});

fs.readFile(__dirname + '/configs/control-panel.json', function (error, config) {
    config = JSON.parse(config.toString('utf8'));
    var list = Jedi.PanelsList.$create(config['panels']);
    list.forEach(function (element) {
        console.log('element =>', element.getColumns());
    });
});

Jedi.$create({
    useDebugging : true,
    baseDirectory : __dirname
}, function (error) {
    console.log('error:', this.getPublicDirectory());
    console.log('this:', this);
});


/**
 * @class
 * @name ORM
 * @extends Class
 */
var ORM = Class.$extend({});

/**
 * @class
 * @name ORM.Table
 * @extends Class
 */
ORM.Table = Class.$extend({

    getName : function () {},
    getColumns : function () {},
    update : function () {},
    insert : function () {}

});